use sea_orm::{
  ConnectOptions, ConnectionTrait, Database, DatabaseConnection, DbBackend,
  Statement,
};
use std::{cmp::max, time::Duration};

use crate::config;

pub async fn init() -> anyhow::Result<DatabaseConnection> {
  let db_conf = config::get().database();

  let mut options = ConnectOptions::new(format!(
    "postgres://{}:{}@{}:{}/{}",
    db_conf.user(),
    db_conf.password(),
    db_conf.host(),
    db_conf.port(),
    db_conf.database()
  ));
  let cpus = num_cpus::get() as u32;
  options
    .min_connections(max(cpus * 4, 10))
    .max_connections(max(cpus * 8, 20))
    .connect_timeout(Duration::from_secs(100))
    .acquire_timeout(Duration::from_secs(120))
    .idle_timeout(Duration::from_secs(500))
    .max_lifetime(Duration::from_secs(3600 * 24))
    .sqlx_logging(false)
    .set_schema_search_path(db_conf.schema());

  let db = Database::connect(options).await?;
  db.ping().await?;
  tracing::info!("Database connected successfull");

  log_database_version(&db).await?;

  Ok(db)
}

async fn log_database_version(db: &DatabaseConnection) -> anyhow::Result<()> {
  let version = db
    .query_one(Statement::from_string(
      DbBackend::Postgres,
      "SELECT version()",
    ))
    .await?
    .ok_or_else(|| anyhow::anyhow!("Failed to get database version"))?;

  tracing::info!(
    "Database version: {}",
    version.try_get_by_index::<String>(0)?
  );

  Ok(())
}
